<%!

  Copyright 2016 Facebook, Inc.

  Licensed under the Apache License, Version 2.0 (the "License");
  you may not use this file except in compliance with the License.
  You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

  Unless required by applicable law or agreed to in writing, software
  distributed under the License is distributed on an "AS IS" BASIS,
  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  See the License for the specific language governing permissions and
  limitations under the License.

%><% > Autogen%>
#pragma once

<%#program:optionals?%>
#include <folly/Optional.h>
<%/program:optionals?%>
#include <thrift/lib/cpp2/GeneratedHeaderHelper.h>
#include <thrift/lib/cpp2/Thrift.h>
#include <thrift/lib/cpp2/protocol/Protocol.h>
<%#program:frozen?%>
#include <thrift/lib/cpp/Frozen.h>
<%/program:frozen?%>

<%#program:thrift_includes%>
#include "<%program:include_prefix%><%program:name%>_types.h"
<%/program:thrift_includes%>
<%#program:cpp_includes%>
#include <%cpp_include%>
<%/program:cpp_includes%>
<% > common/push_and_undef_colliding_macros%>

<% > module_types_h/declare_enums%>

<% > module_types_h/struct_indirection%>

<% > module_types_h/forward_declare%>

<% > module_types_h/typedefs%>

<% > module_types_h/hash_and_equal_to%>

<%#program:structs%>
<% > common/namespace_cpp2_begin%>

class <%struct:name%> <%!
%><%^struct:virtual%>final <%/struct:virtual%><%!
%>: private apache::thrift::detail::st::ComparisonOperators<<%struct:name%>><%#struct:exception?%>, public apache::thrift::TException<%/struct:exception?%> {
 public:
<%#struct:union?%>
<% > module_types_h/union_enum%>


  <%struct:name%>()
      : type_(Type::__EMPTY__) {}

<% > module_types_h/union_copy_ctor%>


<% > module_types_h/union_assign_overload%>

<% > module_types_h/union_template_ctor%>
  void __clear();

  <%#struct:virtual%>virtual <%/struct:virtual%>~<%struct:name%>() {
    __clear();
  }
<%#struct:virtual%>

<%/struct:virtual%>
<% > module_types_h/union_storage%>

<%^struct:cpp_noncomparable%>
<% > module_types_h/eq_overload%>
<% > module_types_h/union_lt_overload%>
<%/struct:cpp_noncomparable%>
<% > module_types_h/union_setters%>

<% > module_types_h/union_getters%>
<% > module_types_h/union_mutables%>
<% > module_types_h/union_moves%>
  Type getType() const { return type_; }

  template <class Protocol_>
  uint32_t read(Protocol_* iprot);
  template <class Protocol_>
  uint32_t serializedSize(Protocol_ const* prot_) const;
  template <class Protocol_>
  uint32_t serializedSizeZC(Protocol_ const* prot_) const;
  template <class Protocol_>
  uint32_t write(Protocol_* prot_) const;
 protected:
  template <class T>
  void destruct(T &val) {
    (&val)->~T();
  }

  Type type_;
  storage_type value_;
<%/struct:union?%>
<%^struct:union?%>

<%#struct:is_large?%>
  <%struct:name%>();
<%/struct:is_large?%>
<%^struct:is_large?%>
  <% > module_types_h/base_ctor%>
<%/struct:is_large?%>

<%#struct:exception?%><%#struct:message%>

  explicit <%struct:name%>(const std::string& __message) :
      <%struct:message%>(__message) {}

  explicit <%struct:name%>(std::string&& __message) :
      <%struct:message%>(std::move(__message)) {}
<%/struct:message%><%/struct:exception?%>
  // FragileConstructor for use in initialization lists only.
  <%struct:name%>(apache::thrift::FragileConstructor<% > module_types_h/fragile_ctor_param_list%>);
<% > module_types_h/template_ctor%>
<%#struct:cpp_noexcept_move_ctor%>
<%^struct:fields?%>
  <%struct:name%>(<%struct:name%>&& other) noexcept {}
<%/struct:fields?%>
<%#struct:fields?%>
<%#struct:is_large?%>
  <%struct:name%>(<%struct:name%>&& other) noexcept;
<%/struct:is_large?%>
<%^struct:is_large?%>
<% > module_types_h/move_ctor%>
<%/struct:is_large?%>
<%/struct:fields?%>
<%/struct:cpp_noexcept_move_ctor%>
<%^struct:cpp_noexcept_move_ctor%>

  <%struct:name%>(<%struct:name%>&&) = default;
<%/struct:cpp_noexcept_move_ctor%>
<%^struct:cpp_noncopyable%>
<%^struct:fields_contain_cpp_ref?%>

  <%struct:name%>(const <%struct:name%>&) = default;
<%/struct:fields_contain_cpp_ref?%>
<%#struct:fields_contain_cpp_ref?%>
  <%struct:name%>(const <%struct:name%>& src);
<%/struct:fields_contain_cpp_ref?%>
<%/struct:cpp_noncopyable%>

  <%struct:name%>& operator=(<%struct:name%>&&) = default;
<%^struct:cpp_noncopyable%>
<%^struct:fields_contain_cpp_ref?%>

  <%struct:name%>& operator=(const <%struct:name%>&) = default;
<%/struct:fields_contain_cpp_ref?%>
<%#struct:fields_contain_cpp_ref?%>
  <%struct:name%>& operator=(const <%struct:name%>& src);
<%/struct:fields_contain_cpp_ref?%>
<%/struct:cpp_noncopyable%>
  void __clear();
<%^struct:virtual%>
<%#struct:is_large?%>

  ~<%struct:name%>();

<%/struct:is_large?%>
<%/struct:virtual%>
<%#struct:virtual%>

<%^struct:is_large?%>
  virtual ~<%struct:name%>() {}
<%/struct:is_large?%>
<%#struct:is_large?%>
  virtual ~<%struct:name%>();
<%/struct:is_large?%>

<%/struct:virtual%>
<%#struct:fields?%>
<% > module_types_h/declare_members%>
<%/struct:fields?%>
<%^struct:cpp_noncomparable%>
<% > module_types_h/eq_overload%>
<% > module_types_h/lt_overload%>
<%/struct:cpp_noncomparable%>
<%#struct:fields?%><%^struct:optionals?%><%^struct:no_getters_setters?%>
<% > module_types_h/getters_setters%>
<%/struct:no_getters_setters?%><%/struct:optionals?%><%/struct:fields?%>

  template <class Protocol_>
  uint32_t read(Protocol_* iprot);
  template <class Protocol_>
  uint32_t serializedSize(Protocol_ const* prot_) const;
  template <class Protocol_>
  uint32_t serializedSizeZC(Protocol_ const* prot_) const;
  template <class Protocol_>
  uint32_t write(Protocol_* prot_) const;
<%#struct:exception?%>

  const char* what() const noexcept override {
<%#struct:message%>
    return <%struct:message%>.c_str();
<%/struct:message%>
<%^struct:message%>
    return "<% > common/namespace_cpp2%><%struct:name%>";
<%/struct:message%>
  }
<%/struct:exception?%>
<%/struct:union?%>
<%#struct:cpp_methods%>
  // user defined code (cpp2.methods = ...)
  <%struct:cpp_methods%>
<%/struct:cpp_methods%>

 private:
  static void translateFieldName(FOLLY_MAYBE_UNUSED folly::StringPiece _fname, FOLLY_MAYBE_UNUSED int16_t& fid, FOLLY_MAYBE_UNUSED apache::thrift::protocol::TType& _ftype);

  template <class Protocol_>
  void readNoXfer(Protocol_* iprot);

  friend class ::apache::thrift::Cpp2Ops< <%struct:name%> >;
};

void swap(<%struct:name%>& a, <%struct:name%>& b);
extern template void <%struct:name%>::readNoXfer<>(apache::thrift::BinaryProtocolReader*);
extern template uint32_t <%struct:name%>::write<>(apache::thrift::BinaryProtocolWriter*) const;
extern template uint32_t <%struct:name%>::serializedSize<>(apache::thrift::BinaryProtocolWriter const*) const;
extern template uint32_t <%struct:name%>::serializedSizeZC<>(apache::thrift::BinaryProtocolWriter const*) const;
extern template void <%struct:name%>::readNoXfer<>(apache::thrift::CompactProtocolReader*);
extern template uint32_t <%struct:name%>::write<>(apache::thrift::CompactProtocolWriter*) const;
extern template uint32_t <%struct:name%>::serializedSize<>(apache::thrift::CompactProtocolWriter const*) const;
extern template uint32_t <%struct:name%>::serializedSizeZC<>(apache::thrift::CompactProtocolWriter const*) const;
<%#program:json?%>
extern template void <%struct:name%>::readNoXfer<>(apache::thrift::SimpleJSONProtocolReader*);
extern template uint32_t <%struct:name%>::write<>(apache::thrift::SimpleJSONProtocolWriter*) const;
extern template uint32_t <%struct:name%>::serializedSize<>(apache::thrift::SimpleJSONProtocolWriter const*) const;
extern template uint32_t <%struct:name%>::serializedSizeZC<>(apache::thrift::SimpleJSONProtocolWriter const*) const;
<%/program:json?%>

template <class Protocol_>
uint32_t <%struct:name%>::read(Protocol_* iprot) {
  auto _xferStart = iprot->getCurrentPosition().getCurrentPosition();
  readNoXfer(iprot);
  return iprot->getCurrentPosition().getCurrentPosition() - _xferStart;
}

<% > common/namespace_cpp2_end%>

namespace apache { namespace thrift {

template <> inline void Cpp2Ops<<% > common/namespace_cpp2%><%struct:name%>>::clear(<% > common/namespace_cpp2%><%struct:name%>* obj) {
  return obj->__clear();
}

template <> inline constexpr apache::thrift::protocol::TType Cpp2Ops<<% > common/namespace_cpp2%><%struct:name%>>::thriftType() {
  return apache::thrift::protocol::T_STRUCT;
}

template <> template <class Protocol> uint32_t Cpp2Ops<<% > common/namespace_cpp2%><%struct:name%>>::write(Protocol* proto, <% > common/namespace_cpp2%><%struct:name%> const* obj) {
  return obj->write(proto);
}

template <> template <class Protocol> void Cpp2Ops<<% > common/namespace_cpp2%><%struct:name%>>::read(Protocol* proto, <% > common/namespace_cpp2%><%struct:name%>* obj) {
  return obj->readNoXfer(proto);
}

template <> template <class Protocol> uint32_t Cpp2Ops<<% > common/namespace_cpp2%><%struct:name%>>::serializedSize(Protocol const* proto, <% > common/namespace_cpp2%><%struct:name%> const* obj) {
  return obj->serializedSize(proto);
}

template <> template <class Protocol> uint32_t Cpp2Ops<<% > common/namespace_cpp2%><%struct:name%>>::serializedSizeZC(Protocol const* proto, <% > common/namespace_cpp2%><%struct:name%> const* obj) {
  return obj->serializedSizeZC(proto);
}

<% > module_types_h/frozen%>
}} // apache::thrift
<%/program:structs%>
<% > common/pop_colliding_macros%>
